﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;

namespace PixelWarfare
{
    /// <summary>
    /// A menu item that cycles through a given array of options when clicked on.
    /// </summary>
    class OptionMenuItem : IMenuItem
    {
        #region Fields

        private string text;
        private string[] options;

        private int x;
        private int y;
        private int index;

        private Font textFont;
        private Font optionsFont;

        private Color onColor;              // Color when the mouse is over the item.
        private Color offColor;             // Color when the mouse is noy over the item.

        private bool mouseOver;             // If the mouse is over the menu item.

        private RectangleF textRec;         // The rectangle the main text.
        private RectangleF[] optionsRecs;   // The rectangles for the options text.
        private RectangleF wholeRec;        // The rectangle for the entire item.

        private OnClick clickEvent;         // The method that runs when the button is clicked.

        private Boolean visible;

        #endregion

        #region Constructors

        /// <summary>
        /// Create a new OptionMenuItem with the given parameters.
        /// </summary>
        /// <param name="text">"Main item text"</param>
        /// <param name="options">"Array of options item will cycle through when clicked."</param>
        /// <param name="x">"X coordinate to center at."</param>
        /// <param name="y">"X coordinate to center at."</param>
        /// <param name="font">"Font to draw the text with."</param>
        /// <param name="onColor">"Color when the mouse is over the item."</param>
        /// <param name="offColor">"Color when the mouse is not over the item."</param>
        /// <param name="clicked">"Method to run when the item is clicked."</param>
        public OptionMenuItem(string text, string[] options, int x, int y, Font font, Color onColor, Color offColor, OnClick clicked)
        {
            this.text = text;
            this.options = options;

            // Start at the first option.
            index = 0;

            this.x = x;
            this.y = y;
            
            this.textFont = font;

            // Options are drawn smaller then the main text.
            this.optionsFont = new Font(font.SystemFontName, font.Size - 10);

            this.onColor = onColor;
            this.offColor = offColor;


            /* Rectangle Bounds can only be defined with a graphics object,
             * So until they are first drawn they are made empty. 
             */
            textRec = new RectangleF();
            optionsRecs = new RectangleF[options.Length];
            wholeRec = new RectangleF();

            for (int i = 0; i < optionsRecs.Length;i++)
            {
                optionsRecs[i] = new RectangleF();
            }

            mouseOver = false;
            visible = true;

            clickEvent = clicked;
        }

        #endregion

        #region Public Methods

        /// <summary>
        /// Draw the text centered with the current option drawn underneath.
        /// Also draw a surrounding box with a minimum size.
        /// </summary>
        /// <param name="g">The graphics to drawn on.</param>
        public void Draw(Graphics g)
        {
            // Only draw if were visible.
            if (!visible)
                return;

            // Fill in the main text Rec if you haven't yet.
            if (textRec.IsEmpty)
            {
                SizeF bounds = g.MeasureString(text, textFont); // So we know where to centre.
                textRec.X = (x - bounds.Width / 2);
                textRec.Y = (y - bounds.Height / 2);
                textRec.Height = bounds.Height;
                textRec.Width = bounds.Width;
            }

            /* Each option can be a different length, so each one also needs a Rec.
             * The whole rec can also be affected by the options if they are longer
             * then the main text, so it is also calculated here. */
            if (optionsRecs[index].IsEmpty)
            {  
                SizeF bounds = g.MeasureString(options[index], optionsFont); // So we know where to centre.
                optionsRecs[index].X = (x - bounds.Width / 2);
                optionsRecs[index].Y = ((y - (bounds.Height + textRec.Height) / 2) + textRec.Height);
                optionsRecs[index].Height = bounds.Height;
                optionsRecs[index].Width = bounds.Width;

                textRec.Y = (y - (bounds.Height + textRec.Height) / 2);

                wholeRec.X = Math.Min(Math.Min(textRec.X, optionsRecs[index].X) - 5, x - 70);
                wholeRec.Y = textRec.Y - 5;
                wholeRec.Width = Math.Max(Math.Max(textRec.Width, optionsRecs[index].Width) + 10, 140);
                wholeRec.Height = textRec.Height + optionsRecs[index].Height + 10;
            }

            if (mouseOver)
            {
                // Draw the outer box.
                g.FillRectangle(new SolidBrush(onColor), wholeRec);
                g.FillRectangle(new SolidBrush(Color.Black), wholeRec.X + 5, wholeRec.Y + 5, 
                    wholeRec.Width - 10, wholeRec.Height - 10);

                // Draw the text.
                g.DrawString(text, textFont, new SolidBrush(onColor), textRec);
                g.DrawString(options[index], optionsFont, new SolidBrush(onColor), optionsRecs[index]);
            }
            else
            {
                g.FillRectangle(new SolidBrush(offColor), wholeRec);
                g.FillRectangle(new SolidBrush(Color.Black), wholeRec.X + 5, wholeRec.Y + 5,
                    wholeRec.Width - 10, wholeRec.Height - 10);

                g.DrawString(text, textFont, new SolidBrush(offColor), textRec);
                g.DrawString(options[index], optionsFont, new SolidBrush(offColor), optionsRecs[index]);
            }

        }

        /// <summary>
        /// If the mouse is over the item then change mouse over to true
        /// which causes the text to be drawn in the onColor.
        /// Otherwise set it to be false and the text is drawn in the offColor.
        /// </summary>
        /// <param name="x">X coordinate of the current mouse location.</param>
        /// <param name="y">X coordinate of the current mouse location.</param>
        public void MouseMove(int x, int y)
        {
            if (visible && wholeRec.Contains(x, y))
            {
                mouseOver = true;
            }
            else
            {
                mouseOver = false;
            }
        }

        /// <summary>
        /// Everytime the mouse is pressed on the item, go to the next option.
        /// ie. increase in index by 1.
        /// And run the onClick event.
        /// </summary>
        /// <param name="x">X coordinate of the mouse click.</param>
        /// <param name="y">Y coordinate of the mouse click.</param>
        public void MousePress(int x, int y)
        {
            if (visible && wholeRec.Contains(x, y))
            {
                clickEvent();
                index = (index + 1) % options.Length;
            }

        }

        /// <summary>
        /// Nothing needs to happen on update.
        /// </summary>
        public void Update() { }

        #endregion

        #region Properties

        public bool Visible
        {
            get { return visible; }
            set { visible = value; }
        }

        #endregion
    }
}
